<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import { ref, onMounted } from "vue";
import {
  addLargeGroundPlane,
  applyMeshNormalMaterial, applyMeshStandardMaterial,
  initDefaultLighting,
  redrawGeometryAndUpdateUI
} from "@/book/ThreeUtils";
import {FontLoader} from "three/examples/jsm/loaders/FontLoader";
import {TextGeometry} from "three/examples/jsm/geometries/TextGeometry";
// 画布
const canvas = ref();
// 场景
const scene = new THREE.Scene();
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.set(-30, 50, 40);
camera.lookAt(0, 0, 0);
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
// 性能统计
const stat = Stats();
// 光照
initDefaultLighting(scene, undefined);
// 地面
const groundPlane = addLargeGroundPlane(scene, false);
// gui
const gui = new GUI();
const controls = new function () {

  this.appliedMaterial = applyMeshNormalMaterial;
  this.castShadow = true;
  this.groundPlaneVisible = true;

  this.size = 90;
  this.height = 90;
  this.bevelThickness = 2;
  this.bevelSize = 0.5;
  this.bevelEnabled = true;
  this.bevelSegments = 3;
  this.bevelEnabled = true;
  this.curveSegments = 12;
  this.steps = 1;
  this.fontName = "bitstream vera sans mono";

  // redraw function, updates the control UI and recreates the geometry.
  this.redraw = function () {
    switch (controls.fontName) {
      case 'bitstream vera sans mono':
        controls.font = font_bitstream
        break;
      case 'helvetiker':
        controls.font = font_helvetiker_regular
        break;
      case 'helvetiker bold':
        controls.font = font_helvetiker_bold
        break;
    }

    redrawGeometryAndUpdateUI(gui, scene, controls, function() {
      var options = {
        size: controls.size,
        height: controls.height,
        weight: controls.weight,
        font: controls.font,
        bevelThickness: controls.bevelThickness,
        bevelSize: controls.bevelSize,
        bevelSegments: controls.bevelSegments,
        bevelEnabled: controls.bevelEnabled,
        curveSegments: controls.curveSegments,
        steps: controls.steps
      };

      const geom = new TextGeometry("Learning Three.js", options)
      geom.applyMatrix4(new THREE.Matrix4().makeScale(0.05,0.05,0.05));
      geom.center();

      return geom
    });
  };
};

// 字体
let font_bitstream;
let font_helvetiker_bold;
let font_helvetiker_regular;

const fontload1 = new FontLoader();
fontload1.load(
    new URL("@/assets/fonts/bitstream_vera_sans_mono_roman.typeface.json", import.meta.url).href,
    (response) => {
      controls.font = response;
      font_bitstream = response;
      controls.redraw();
      render();
    }
);

const fontload2 = new FontLoader();
fontload2.load(
    new URL('@/assets/fonts/helvetiker_bold.typeface.json', import.meta.url).href,
    (response) => {
      font_helvetiker_bold = response;
    }
);

const fontload3 = new FontLoader();
fontload3.load(
    new URL('@/assets/fonts/helvetiker_regular.typeface.json', import.meta.url).href,
    (response) => {
      font_helvetiker_regular = response;
    }
);
// @ts-ignore
gui.add(controls, 'size', 0, 200).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'height', 0, 200).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'fontName', ['bitstream vera sans mono', 'helvetiker', 'helvetiker bold']).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'bevelThickness', 0, 10).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'bevelSize', 0, 10).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'bevelSegments', 0, 30).step(1).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'bevelEnabled').onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'curveSegments', 1, 30).step(1).onChange(controls.redraw);
// @ts-ignore
gui.add(controls, 'steps', 1, 5).step(1).onChange(controls.redraw);

// @ts-ignore
gui.add(controls, 'appliedMaterial', {
  meshNormal: applyMeshNormalMaterial,
  meshStandard: applyMeshStandardMaterial,
}).onChange(controls.redraw)
// @ts-ignore
gui.add(controls, 'castShadow').onChange(function(e) {controls.mesh.castShadow = e})
// @ts-ignore
gui.add(controls, 'groundPlaneVisible').onChange(function(e) {groundPlane.material.visible = e})

let step = 0;
const render = () => {
  stat.update();
  orbitControl.update();

  step += 0.005;

  controls.mesh.rotation.y = step;
  controls.mesh.rotation.x = step;
  controls.mesh.rotation.z = step;

  requestAnimationFrame(render);
  renderer.render(scene, camera);
};

onMounted(() => {
  canvas.value.appendChild(stat.domElement);
  canvas.value.appendChild(renderer.domElement);
  render();
});
</script>
